如何检测元素外部的单击? 您所在的位置:网站首页 getboundingclientrect offsetwidth 如何检测元素外部的单击?

如何检测元素外部的单击?

#如何检测元素外部的单击?| 来源: 网络整理| 查看: 265

我有一些HTML菜单,当用户点击这些菜单的头部时,我会完全显示.当用户点击菜单区域外时,我想隐藏这些元素.

jQuery可以这样吗?

$("#menuscontainer").clickOutsideThisElement(function() { // Hide the menus }); 问题回答

注意:使用stopEventPropagation()是应该避免的,因为它破坏了DOM中的正常事件流.有关更多信息,请参阅此文章.考虑使用这种方法,而不是

将单击事件附加到关闭窗口的文档正文.将单独的单击事件附加到容器,该容器将停止传播到文档正文.

$(window).click(function() { //Hide the menus if visible }); $('#menucontainer').click(function(event){ event.stopPropagation(); }); 问题回答

您可以侦听单击事件document,然后通过使用确保#menucontainer不是祖先或单击元素的目标 .closest().

如果不是,则单击的元素位于其外部,#menucontainer您可以安全地隐藏它.

$(document).click(function(event) { $target = $(event.target); if(!$target.closest('#menucontainer').length && $('#menucontainer').is(":visible")) { $('#menucontainer').hide(); } }); 编辑 - 2017-06-23

如果您打算关闭菜单并想要停止侦听事件,也可以在事件监听器之后进行清理.此函数将仅清除新创建的侦听器,并保留其他任何单击侦听器document.使用ES2015语法:

export function hideOnClickOutside(selector) { const outsideClickListener = (event) => { $target = $(event.target); if (!$target.closest(selector).length && $(selector).is(':visible')) { $(selector).hide(); removeClickListener(); } } const removeClickListener = () => { document.removeEventListener('click', outsideClickListener) } document.addEventListener('click', outsideClickListener) } 编辑 - 2018-03-11

对于那些不想使用jQuery的人.这是普通vanillaJS(ECMAScript6)中的上述代码.

function hideOnClickOutside(element) { const outsideClickListener = event => { if (!element.contains(event.target) && isVisible(element)) { // or use: event.target.closest(selector) === null element.style.display = 'none' removeClickListener() } } const removeClickListener = () => { document.removeEventListener('click', outsideClickListener) } document.addEventListener('click', outsideClickListener) } const isVisible = elem => !!elem && !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ) // source (2018-03-11): https://github.com/jquery/jquery/blob/master/src/css/hiddenVisibleSelectors.js

注意:这是基于Alex注释!element.contains(event.target)而不是使用jQuery部分.

但是element.closest()现在所有主流浏览器都可以使用(W3C版本与jQuery版本略有不同).Polyfills可以在这里找到:https://developer.mozilla.org/en-US/docs/Web/API/Element/closest

问题回答

如何检测元素外的点击?

这个问题如此受欢迎并且答案如此之多的原因在于它看起来很复杂.经过近八年的时间和几十个答案,我真的很惊讶地看到对可访问性的关注度很低.

当用户点击菜单区域外时,我想隐藏这些元素.

这是一个崇高的事业,也是实际问题.问题的标题 - 大多数答案似乎试图解决 - 包含一个不幸的红鲱鱼.

提示:这是"点击"这个词!

您实际上并不想绑定点击处理程序.

如果您绑定了点击处理程序以关闭对话框,那么您已经失败了.你失败的原因是不是每个人都会触发click事件.不使用鼠标的用户将能够通过按下来转义对话框(并且您的弹出菜单可以说是一种对话框)Tab,然后他们将无法在不随后触发click事件的情况下读取对话框后面的内容.

所以让我们重新解释一下这个问题.

当用户完成对话时,如何关闭对话框?

这是目标.不幸的是,现在我们需要绑定userisfinishedwiththedialog事件,并且绑定不是那么简单.

那么我们如何检测用户是否已完成对话框的使用?

focusout事件

一个好的开始是确定焦点是否已离开对话框.

提示:小心blur事件,blur如果事件被绑定到冒泡阶段,则不会传播!

jQuery focusout会做得很好.如果你不能使用jQuery,那么你可以blur在捕获阶段使用:

element.addEventListener('blur', ..., true); // use capture: ^^^^

此外,对于许多对话框,您需要允许容器获得焦点.添加tabindex="-1"以允许对话框动态接收焦点,而不会中断选项卡流.

$('a').on('click', function () { $(this.hash).toggleClass('active').focus(); }); $('div').on('focusout', function () { $(this).removeClass('active'); }); div { display: none; } .active { display: block; } Example Lorem ipsum dolor sit amet. 问题回答

这里的其他解决方案对我不起作用,所以我不得不使用:

if(!$(event.target).is('#foo')) { // hide menu } 问题回答

我有一个与Eran的例子类似的应用程序,除了我打开菜单时将click事件附加到正文...有点像这样:

$('#menucontainer').click(function(event) { $('html').one('click',function() { // Hide the menus }); event.stopPropagation(); });

有关jQuery 功能的更多信息one()

问题回答现在是 2020 年,您可以使用 event.composedPath()

来自:https: //developer.mozilla.org/en-US/docs/Web/API/Event/composedPath

Event 接口的 compositionPath() 方法返回事件的路径,它是将调用侦听器的对象数组。

const target = document.querySelector('#myTarget') document.addEventListener('click', (event) => { const withinBoundaries = event.composedPath().includes(target) if (withinBoundaries) { target.innerText = 'Click happened inside element' } else { target.innerText = 'Click happened **OUTSIDE** element' } }) /* just to make it good looking. you don't need this */ #myTarget { margin: 50px auto; width: 500px; height: 500px; background: gray; border: 10px solid black; } click me (or not!) 问题回答

经过研究,我找到了三种工作方案(我忘了页面链接供参考)

第一解决方案 //The good thing about this solution is it doesn't stop event propagation. var clickFlag = 0; $('body').on('click', function () { if(clickFlag == 0) { console.log('hide element here'); /* Hide element here */ } else { clickFlag=0; } }); $('body').on('click','#testDiv', function (event) { clickFlag = 1; console.log('showed the element'); /* Show the element */ }); 二解决方案 $('body').on('click', function(e) { if($(e.target).closest('#testDiv').length == 0) { /* Hide dropdown here */ } }); 第三种方案 var specifiedElement = document.getElementById('testDiv'); document.addEventListener('click', function(event) { var isClickInside = specifiedElement.contains(event.target); if (isClickInside) { console.log('You clicked inside') } else { console.log('You clicked outside') } }); 问题回答$("#menuscontainer").click(function() { $(this).focus(); }); $("#menuscontainer").blur(function(){ $(this).hide(); });

对我来说就好了.

问题回答

现在有一个插件:外部事件(博客文章)

将clickoutside处理程序(WLOG)绑定到元素时会发生以下情况:

该元素被添加到一个数组中,该数组包含clickoutside处理程序的所有元素a(命名空间)单击处理程序绑定到文档(如果尚未存在)对于文档中的任何单击,触发clickoutside事件,以便该数组中那些不等于或者是click-events目标的父元素的元素另外,clickoutside事件的event.target 设置为用户点击的元素(这样你甚至可以知道用户点击了什么,而不仅仅是他点击了外面)

因此,没有事件停止传播,并且可以在具有外部处理程序的元素"上方"使用其他点击处理程序.

问题回答

这完全适合我!

$('html').click(function (e) { if (e.target.id == 'YOUR-DIV-ID') { //do something } else { //do something } }); 问题回答

我不认为你真正需要的是当用户点击外面时关闭菜单; 您需要的是当用户点击页面上的任何位置时关闭菜单.如果您单击菜单,或关闭菜单,它应该关闭吗?

上面没有找到满意的答案促使我前几天写这篇博文.对于更迂腐的人来说,有许多值得注意的问题:

如果在单击时将click事件处理程序附加到body元素,请确保在关闭菜单之前等待第二次单击,并取消绑定事件.否则,打开菜单的单击事件将冒泡到必须关闭菜单的侦听器.如果对click事件使用event.stopPropogation(),则页面中没有其他元素可以具有click-anywhere-to-close功能.将click事件处理程序无限期地附加到body元素不是一个高性能的解决方案将事件的目标及其父项与处理程序的创建者进行比较假定您想要的是在单击它时关闭菜单,当您真正想要的是在单击页面上的任何位置时关闭它.在body元素上侦听事件会使代码更加脆弱.造型像无辜一样会破坏它:body { margin-left:auto; margin-right: auto; width:960px;}问题回答

正如另一张海报所说,有很多陷阱,特别是如果您正在显示的元素(在这种情况下是一个菜单)具有交互元素.我发现以下方法相当健壮:

$('#menuscontainer').click(function(event) { //your code that shows the menus fully //now set up an event listener so that clicking anywhere outside will close the menu $('html').click(function(event) { //check up the tree of the click target to check whether user has clicked outside of menu if ($(event.target).parents('#menuscontainer').length==0) { // your code to hide menu //this event listener has done its job so we can unbind it. $(this).unbind(event); } }) }); 问题回答

这种情况的简单解决方案是:

$(document).mouseup(function (e) { var container = $("YOUR SELECTOR"); // Give you class or ID if (!container.is(e.target) && // If the target of the click is not the desired div or section container.has(e.target).length === 0) // ... nor a descendant-child of the container { container.hide(); } });

上面的脚本将隐藏divif divclick事件的外部是否被触发.

您可以在以下博客中查看更多信息:http://www.codecanal.com/detect-click-outside-div-using-javascript/

问题回答解决方法1

而不是使用可能有一些副作用的event.stopPropagation(),只需定义一个简单的标志变量并添加一个if条件.我测试了这个并正常工作,没有任何副作用的stopPropagation:

var flag = "1"; $('#menucontainer').click(function(event){ flag = "0"; // flag 0 means click happened in the area where we should not do any action }); $('html').click(function() { if(flag != "0"){ // Hide the menus if visible } else { flag = "1"; } }); 溶液2

只需一个简单的if条件:

$(document).on('click', function(event){ var container = $("#menucontainer"); if (!container.is(event.target) && // If the target of the click isn't the container... container.has(event.target).length === 0) // ... nor a descendant of the container { // Do whatever you want to do when click is outside the element } }); 问题回答

检查窗口单击事件目标(它应传播到窗口,只要它没有在其他任何地方捕获),并确保它不是任何菜单元素.如果不是,那么你就在菜单之外了.

或者检查点击的位置,看看它是否包含在菜单区域中.

问题回答

我有这样的成功:

var $menuscontainer = ...; $('#trigger').click(function() { $menuscontainer.show(); $('body').click(function(event) { var $target = $(event.target); if ($target.parents('#menuscontainer').length == 0) { $menuscontainer.hide(); } }); });

逻辑是:当#menuscontainer显示时,将单击处理程序绑定到#menuscontainer仅在目标(单击)不是它的子项时隐藏的主体.

问题回答

作为变种:

var $menu = $('#menucontainer'); $(document).on('click', function (e) { // If element is opened and click target is outside it, hide it if ($menu.is(':visible') && !$menu.is(e.target) && !$menu.has(e.target).length) { $menu.hide(); } });

停止事件传播没有问题,并且更好地支持同一页面上的多个菜单,在第一个打开时单击第二个菜单将在stopPropagation解决方案中保留第一个菜单.

问题回答用于focusout可访问性

这里有一个答案说(非常正确)关注click事件是一个可访问性问题,因为我们想要满足键盘用户的需求。该focusout事件是在这里使用的正确方法,但它可以比其他答案更简单(也可以在纯 javascript 中):

一种更简单的方法:

使用的“问题”focusout是,如果对话框/模态/菜单中的元素失去焦点,那么事件仍然会被触发。我们可以通过查看event.relatedTarget(它告诉我们哪个元素将获得焦点)来检查情况是否如此。

dialog = document.getElementById("dialogElement") dialog.addEventListener("focusout", function (event) { if ( // we are still inside the dialog so don't close dialog.contains(event.relatedTarget) || // we have switched to another tab so probably don't want to close !document.hasFocus() ) { return; } dialog.close(); // or whatever logic you want to use to close });

上面有一个小问题,那就是relatedTarget可能null。如果用户在对话框外部单击,这很好,但如果除非用户在对话框内部单击并且对话框碰巧不可聚焦,那么这将是一个问题。要解决此问题,您必须确保设置tabIndex=0为可聚焦对话框。

问题回答

我在一些jQuery日历插件中找到了这个方法.

function ClickOutsideCheck(e) { var el = e.target; var popup = $('.popup:visible')[0]; if (popup==undefined) return true; while (true){ if (el == popup ) { return true; } else if (el == document) { $(".popup").hide(); return false; } else { el = $(el).parent()[0]; } } }; $(document).bind('mousedown.popup', ClickOutsideCheck); 问题回答

该事件有一个名为event.path的属性,该属性是"树中所有祖先的静态有序列表".要检查事件是源自特定DOM元素还是其中一个子元素,只需检查该特定DOM元素的路径.它还可以用于通过逻辑OR检查some函数中的元素检查来检查多个元素.

$("body").click(function() { target = document.getElementById("main"); flag = event.path.some(function(el, i, arr) { return (el == target) }) if (flag) { console.log("Inside") } else { console.log("Outside") } }); #main { display: inline-block; } Test-Main Test-Main Test-Main Test-Main Test-Main Outside Main 问题回答

这是针对未来观众的vanilla JavaScript解决方案.

单击文档中的任何元素后,如果切换了单击元素的id,或者未隐藏隐藏元素且隐藏元素不包含单击元素,则切换元素.

(function () { "use strict"; var hidden = document.getElementById('hidden'); document.addEventListener('click', function (e) { if (e.target.id == 'toggle' || (hidden.style.display != 'none' && !hidden.contains(e.target))) hidden.style.display = hidden.style.display == 'none' ? 'block' : 'none'; }, false); })(); (function () { "use strict"; var hidden = document.getElementById('hidden'); document.addEventListener('click', function (e) { if (e.target.id == 'toggle' || (hidden.style.display != 'none' && !hidden.contains(e.target))) hidden.style.display = hidden.style.display == 'none' ? 'block' : 'none'; }, false); })(); Toggle Hidden Div This content is normally hidden. click anywhere other than this content to make me disappear 问题回答

我很惊讶没有人真正认可的focusout事件:

var button = document.getElementById('button'); button.addEventListener('click', function(e){ e.target.style.backgroundColor = 'green'; }); button.addEventListener('focusout', function(e){ e.target.style.backgroundColor = ''; }); Click 问题回答

如果你是IE和FF 3.*的脚本,你只想知道某个框区域内是否发生了点击,你也可以使用类似的东西:

this.outsideElementClick = function(objEvent, objElement){ var objCurrentElement = objEvent.target || objEvent.srcElement; var blnInsideX = false; var blnInsideY = false; if (objCurrentElement.getBoundingClientRect().left >= objElement.getBoundingClientRect().left && objCurrentElement.getBoundingClientRect().right = objElement.getBoundingClientRect().top && objCurrentElement.getBoundingClientRect().bottom


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有